/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package it.polimi.games.epkb.controller;

import it.polimi.games.epkb.controller.exceptions.IllegalOrphanException;
import it.polimi.games.epkb.controller.exceptions.NonexistentEntityException;
import it.polimi.games.epkb.controller.exceptions.PreexistingEntityException;
import it.polimi.games.epkb.entityClasses.Predicate;
import java.io.Serializable;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Query;
import javax.persistence.EntityNotFoundException;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;
import it.polimi.games.epkb.entityClasses.GpiKpi;
import java.util.ArrayList;
import java.util.Collection;
import it.polimi.games.epkb.entityClasses.Rule;
import it.polimi.games.epkb.entityClasses.ExecutedRules;
import javax.transaction.UserTransaction;

/**
 *
 * @author plebani
 */
public class PredicateJpaController implements Serializable {

    public PredicateJpaController(EntityManagerFactory emf) {
        this.utx = null;
        this.emf = emf;
    }

    public PredicateJpaController(UserTransaction utx, EntityManagerFactory emf) {
        this.utx = utx;
        this.emf = emf;
    }
    private UserTransaction utx = null;
    private EntityManagerFactory emf = null;

    public EntityManager getEntityManager() {
        return emf.createEntityManager();
    }

    public void create(Predicate predicate) throws PreexistingEntityException, Exception {
        if (predicate.getGpiKpiCollection() == null) {
            predicate.setGpiKpiCollection(new ArrayList<GpiKpi>());
        }
        if (predicate.getRuleCollection() == null) {
            predicate.setRuleCollection(new ArrayList<Rule>());
        }
        if (predicate.getExecutedRulesCollection() == null) {
            predicate.setExecutedRulesCollection(new ArrayList<ExecutedRules>());
        }
        EntityManager em = null;
        try {
            em = getEntityManager();
            em.getTransaction().begin();
            Collection<GpiKpi> attachedGpiKpiCollection = new ArrayList<GpiKpi>();
            for (GpiKpi gpiKpiCollectionGpiKpiToAttach : predicate.getGpiKpiCollection()) {
                gpiKpiCollectionGpiKpiToAttach = em.getReference(gpiKpiCollectionGpiKpiToAttach.getClass(), gpiKpiCollectionGpiKpiToAttach.getId());
                attachedGpiKpiCollection.add(gpiKpiCollectionGpiKpiToAttach);
            }
            predicate.setGpiKpiCollection(attachedGpiKpiCollection);
            Collection<Rule> attachedRuleCollection = new ArrayList<Rule>();
            for (Rule ruleCollectionRuleToAttach : predicate.getRuleCollection()) {
                ruleCollectionRuleToAttach = em.getReference(ruleCollectionRuleToAttach.getClass(), ruleCollectionRuleToAttach.getId());
                attachedRuleCollection.add(ruleCollectionRuleToAttach);
            }
            predicate.setRuleCollection(attachedRuleCollection);
            Collection<ExecutedRules> attachedExecutedRulesCollection = new ArrayList<ExecutedRules>();
            for (ExecutedRules executedRulesCollectionExecutedRulesToAttach : predicate.getExecutedRulesCollection()) {
                executedRulesCollectionExecutedRulesToAttach = em.getReference(executedRulesCollectionExecutedRulesToAttach.getClass(), executedRulesCollectionExecutedRulesToAttach.getId());
                attachedExecutedRulesCollection.add(executedRulesCollectionExecutedRulesToAttach);
            }
            predicate.setExecutedRulesCollection(attachedExecutedRulesCollection);
            em.persist(predicate);
            for (GpiKpi gpiKpiCollectionGpiKpi : predicate.getGpiKpiCollection()) {
                gpiKpiCollectionGpiKpi.getPredicateCollection().add(predicate);
                gpiKpiCollectionGpiKpi = em.merge(gpiKpiCollectionGpiKpi);
            }
            for (Rule ruleCollectionRule : predicate.getRuleCollection()) {
                ruleCollectionRule.getPredicateCollection().add(predicate);
                ruleCollectionRule = em.merge(ruleCollectionRule);
            }
            for (ExecutedRules executedRulesCollectionExecutedRules : predicate.getExecutedRulesCollection()) {
                Predicate oldIdPredicateViolatedOfExecutedRulesCollectionExecutedRules = executedRulesCollectionExecutedRules.getIdPredicateViolated();
                executedRulesCollectionExecutedRules.setIdPredicateViolated(predicate);
                executedRulesCollectionExecutedRules = em.merge(executedRulesCollectionExecutedRules);
                if (oldIdPredicateViolatedOfExecutedRulesCollectionExecutedRules != null) {
                    oldIdPredicateViolatedOfExecutedRulesCollectionExecutedRules.getExecutedRulesCollection().remove(executedRulesCollectionExecutedRules);
                    oldIdPredicateViolatedOfExecutedRulesCollectionExecutedRules = em.merge(oldIdPredicateViolatedOfExecutedRulesCollectionExecutedRules);
                }
            }
            em.getTransaction().commit();
        } catch (Exception ex) {
            if (findPredicate(predicate.getId()) != null) {
                throw new PreexistingEntityException("Predicate " + predicate + " already exists.", ex);
            }
            throw ex;
        } finally {
            if (em != null) {
                em.close();
            }
        }
    }

    public void edit(Predicate predicate) throws IllegalOrphanException, NonexistentEntityException, Exception {
        EntityManager em = null;
        try {
            em = getEntityManager();
            em.getTransaction().begin();
            Predicate persistentPredicate = em.find(Predicate.class, predicate.getId());
            Collection<GpiKpi> gpiKpiCollectionOld = persistentPredicate.getGpiKpiCollection();
            Collection<GpiKpi> gpiKpiCollectionNew = predicate.getGpiKpiCollection();
            Collection<Rule> ruleCollectionOld = persistentPredicate.getRuleCollection();
            Collection<Rule> ruleCollectionNew = predicate.getRuleCollection();
            Collection<ExecutedRules> executedRulesCollectionOld = persistentPredicate.getExecutedRulesCollection();
            Collection<ExecutedRules> executedRulesCollectionNew = predicate.getExecutedRulesCollection();
            List<String> illegalOrphanMessages = null;
            for (ExecutedRules executedRulesCollectionOldExecutedRules : executedRulesCollectionOld) {
                if (!executedRulesCollectionNew.contains(executedRulesCollectionOldExecutedRules)) {
                    if (illegalOrphanMessages == null) {
                        illegalOrphanMessages = new ArrayList<String>();
                    }
                    illegalOrphanMessages.add("You must retain ExecutedRules " + executedRulesCollectionOldExecutedRules + " since its idPredicateViolated field is not nullable.");
                }
            }
            if (illegalOrphanMessages != null) {
                throw new IllegalOrphanException(illegalOrphanMessages);
            }
            Collection<GpiKpi> attachedGpiKpiCollectionNew = new ArrayList<GpiKpi>();
            for (GpiKpi gpiKpiCollectionNewGpiKpiToAttach : gpiKpiCollectionNew) {
                gpiKpiCollectionNewGpiKpiToAttach = em.getReference(gpiKpiCollectionNewGpiKpiToAttach.getClass(), gpiKpiCollectionNewGpiKpiToAttach.getId());
                attachedGpiKpiCollectionNew.add(gpiKpiCollectionNewGpiKpiToAttach);
            }
            gpiKpiCollectionNew = attachedGpiKpiCollectionNew;
            predicate.setGpiKpiCollection(gpiKpiCollectionNew);
            Collection<Rule> attachedRuleCollectionNew = new ArrayList<Rule>();
            for (Rule ruleCollectionNewRuleToAttach : ruleCollectionNew) {
                ruleCollectionNewRuleToAttach = em.getReference(ruleCollectionNewRuleToAttach.getClass(), ruleCollectionNewRuleToAttach.getId());
                attachedRuleCollectionNew.add(ruleCollectionNewRuleToAttach);
            }
            ruleCollectionNew = attachedRuleCollectionNew;
            predicate.setRuleCollection(ruleCollectionNew);
            Collection<ExecutedRules> attachedExecutedRulesCollectionNew = new ArrayList<ExecutedRules>();
            for (ExecutedRules executedRulesCollectionNewExecutedRulesToAttach : executedRulesCollectionNew) {
                executedRulesCollectionNewExecutedRulesToAttach = em.getReference(executedRulesCollectionNewExecutedRulesToAttach.getClass(), executedRulesCollectionNewExecutedRulesToAttach.getId());
                attachedExecutedRulesCollectionNew.add(executedRulesCollectionNewExecutedRulesToAttach);
            }
            executedRulesCollectionNew = attachedExecutedRulesCollectionNew;
            predicate.setExecutedRulesCollection(executedRulesCollectionNew);
            predicate = em.merge(predicate);
            for (GpiKpi gpiKpiCollectionOldGpiKpi : gpiKpiCollectionOld) {
                if (!gpiKpiCollectionNew.contains(gpiKpiCollectionOldGpiKpi)) {
                    gpiKpiCollectionOldGpiKpi.getPredicateCollection().remove(predicate);
                    gpiKpiCollectionOldGpiKpi = em.merge(gpiKpiCollectionOldGpiKpi);
                }
            }
            for (GpiKpi gpiKpiCollectionNewGpiKpi : gpiKpiCollectionNew) {
                if (!gpiKpiCollectionOld.contains(gpiKpiCollectionNewGpiKpi)) {
                    gpiKpiCollectionNewGpiKpi.getPredicateCollection().add(predicate);
                    gpiKpiCollectionNewGpiKpi = em.merge(gpiKpiCollectionNewGpiKpi);
                }
            }
            for (Rule ruleCollectionOldRule : ruleCollectionOld) {
                if (!ruleCollectionNew.contains(ruleCollectionOldRule)) {
                    ruleCollectionOldRule.getPredicateCollection().remove(predicate);
                    ruleCollectionOldRule = em.merge(ruleCollectionOldRule);
                }
            }
            for (Rule ruleCollectionNewRule : ruleCollectionNew) {
                if (!ruleCollectionOld.contains(ruleCollectionNewRule)) {
                    ruleCollectionNewRule.getPredicateCollection().add(predicate);
                    ruleCollectionNewRule = em.merge(ruleCollectionNewRule);
                }
            }
            for (ExecutedRules executedRulesCollectionNewExecutedRules : executedRulesCollectionNew) {
                if (!executedRulesCollectionOld.contains(executedRulesCollectionNewExecutedRules)) {
                    Predicate oldIdPredicateViolatedOfExecutedRulesCollectionNewExecutedRules = executedRulesCollectionNewExecutedRules.getIdPredicateViolated();
                    executedRulesCollectionNewExecutedRules.setIdPredicateViolated(predicate);
                    executedRulesCollectionNewExecutedRules = em.merge(executedRulesCollectionNewExecutedRules);
                    if (oldIdPredicateViolatedOfExecutedRulesCollectionNewExecutedRules != null && !oldIdPredicateViolatedOfExecutedRulesCollectionNewExecutedRules.equals(predicate)) {
                        oldIdPredicateViolatedOfExecutedRulesCollectionNewExecutedRules.getExecutedRulesCollection().remove(executedRulesCollectionNewExecutedRules);
                        oldIdPredicateViolatedOfExecutedRulesCollectionNewExecutedRules = em.merge(oldIdPredicateViolatedOfExecutedRulesCollectionNewExecutedRules);
                    }
                }
            }
            em.getTransaction().commit();
        } catch (Exception ex) {
            String msg = ex.getLocalizedMessage();
            if (msg == null || msg.length() == 0) {
                String id = predicate.getId();
                if (findPredicate(id) == null) {
                    throw new NonexistentEntityException("The predicate with id " + id + " no longer exists.");
                }
            }
            throw ex;
        } finally {
            if (em != null) {
                em.close();
            }
        }
    }

    public void destroy(String id) throws IllegalOrphanException, NonexistentEntityException {
        EntityManager em = null;
        try {
            em = getEntityManager();
            em.getTransaction().begin();
            Predicate predicate;
            try {
                predicate = em.getReference(Predicate.class, id);
                predicate.getId();
            } catch (EntityNotFoundException enfe) {
                throw new NonexistentEntityException("The predicate with id " + id + " no longer exists.", enfe);
            }
            List<String> illegalOrphanMessages = null;
            Collection<ExecutedRules> executedRulesCollectionOrphanCheck = predicate.getExecutedRulesCollection();
            for (ExecutedRules executedRulesCollectionOrphanCheckExecutedRules : executedRulesCollectionOrphanCheck) {
                if (illegalOrphanMessages == null) {
                    illegalOrphanMessages = new ArrayList<String>();
                }
                illegalOrphanMessages.add("This Predicate (" + predicate + ") cannot be destroyed since the ExecutedRules " + executedRulesCollectionOrphanCheckExecutedRules + " in its executedRulesCollection field has a non-nullable idPredicateViolated field.");
            }
            if (illegalOrphanMessages != null) {
                throw new IllegalOrphanException(illegalOrphanMessages);
            }
            Collection<GpiKpi> gpiKpiCollection = predicate.getGpiKpiCollection();
            for (GpiKpi gpiKpiCollectionGpiKpi : gpiKpiCollection) {
                gpiKpiCollectionGpiKpi.getPredicateCollection().remove(predicate);
                gpiKpiCollectionGpiKpi = em.merge(gpiKpiCollectionGpiKpi);
            }
            Collection<Rule> ruleCollection = predicate.getRuleCollection();
            for (Rule ruleCollectionRule : ruleCollection) {
                ruleCollectionRule.getPredicateCollection().remove(predicate);
                ruleCollectionRule = em.merge(ruleCollectionRule);
            }
            em.remove(predicate);
            em.getTransaction().commit();
        } finally {
            if (em != null) {
                em.close();
            }
        }
    }

    public List<Predicate> findPredicateEntities() {
        return findPredicateEntities(true, -1, -1);
    }

    public List<Predicate> findPredicateEntities(int maxResults, int firstResult) {
        return findPredicateEntities(false, maxResults, firstResult);
    }

    private List<Predicate> findPredicateEntities(boolean all, int maxResults, int firstResult) {
        EntityManager em = getEntityManager();
        try {
            CriteriaQuery cq = em.getCriteriaBuilder().createQuery();
            cq.select(cq.from(Predicate.class));
            Query q = em.createQuery(cq);
            if (!all) {
                q.setMaxResults(maxResults);
                q.setFirstResult(firstResult);
            }
            return q.getResultList();
        } finally {
            em.close();
        }
    }

    public Predicate findPredicate(String id) {
        EntityManager em = getEntityManager();
        try {
            return em.find(Predicate.class, id);
        } finally {
            em.close();
        }
    }

    public int getPredicateCount() {
        EntityManager em = getEntityManager();
        try {
            CriteriaQuery cq = em.getCriteriaBuilder().createQuery();
            Root<Predicate> rt = cq.from(Predicate.class);
            cq.select(em.getCriteriaBuilder().count(rt));
            Query q = em.createQuery(cq);
            return ((Long) q.getSingleResult()).intValue();
        } finally {
            em.close();
        }
    }
    
}
